package com.jisf.driver.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jisf.driver.auth.MyPasswordEncoder;
import com.jisf.driver.filter.JwtAuthenticationTokenFilter;
import com.jisf.driver.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @Classname SecurityConfig
 * @Description TODO
 * @Date 2022/2/20 15:19
 * @Created by jisf：【429627912@qq.com】
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsServiceImpl;

    @Autowired
    private MyPasswordEncoder myPasswordEncoder;

    @Autowired
    private ObjectMapper objectMapper;

//    /**
//     * 登陆成功的处理器
//     */
//    @Autowired
//    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
//
//    /**
//     * 登录失败的处理器
//     */
//    @Autowired
//    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
//
//    /**
//     * 未登录访问资源时异常
//     */
//    @Autowired
//    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;
//
//    /**
//     * 权限不足处理异常
//     */
//    @Autowired
//    private MyAccessDeniedHandler myAccessDeniedHandler;
//
//    /**
//     * 注销的处理器
//     */
//    @Autowired
//    private MyLogoutHandler myLogoutHandler;
//
//    /**
//     * 注销成功的处理器
//     */
//    @Autowired
//    private MyLogoutSuccessHandler myLogoutSuccessHandler;
//
//    /**
//     * 会话超时管理
//     */
//    @Autowired
//    private MyInvalidSessionStrategy myInvalidSessionStrategy;
//
//    /**
//     * 用户被挤下线的处理
//     */
//    @Autowired
//    private MyExpiredSessionStrategy myExpiredSessionStrategy;

    /**
     * Jwt认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    /**
     * 认证失败处理器
     */
    @Autowired
    private AuthenticationEntryPoint authenticationEntryPointImpl;

    /**
     * 授权失败处理器
     */
    @Autowired
    private AccessDeniedHandler accessDeniedHandlerImpl;

    //注入数据源
    @Autowired
    private DataSource dataSource;

    //配置操作数据库对象
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

//    @Bean
//    public AuthenticationProvider authenticationProvider() {
//        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
//        //对默认的UserDetailsService进行覆盖
//        authenticationProvider.setUserDetailsService(userDetailsServiceImpl);
//        //对默认的PasswordEncoder进行覆盖
//        authenticationProvider.setPasswordEncoder(myPasswordEncoder);
//        return authenticationProvider;
//    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsServiceImpl).passwordEncoder(myPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

//        //配置退出映射地址
//        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login.html").permitAll();

//        //配置没有权限访问跳转自定义页面
//        http.exceptionHandling().accessDeniedPage("/unauth.html");

        http
//                .formLogin()    //自定义自己编写的登录页面
//                .loginPage("/login.html")   //登录页面设置
//                .loginProcessingUrl("/user/login")  //登录访问路径
//                .defaultSuccessUrl("/test/index").permitAll()   //登陆成功之后，跳转路径
//                .failureUrl("/login.html")  //登陆失败跳转路径
//                .successHandler(myAuthenticationSuccessHandler) //登陆成功的处理器
//                .failureHandler(myAuthenticationFailureHandler) //登录失败的处理器
//                .and().exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint) //未登录访问资源异常
//                .accessDeniedHandler(myAccessDeniedHandler) //权限不足异常
//                .and().logout().permitAll() //允许注销操作
//                .addLogoutHandler(myLogoutHandler)  //注销操作处理器
//                .logoutSuccessHandler(myLogoutSuccessHandler)   //注销成功处理器
//                .deleteCookies("JSESSIONID")    //登出之后删除cookie
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);   //禁用Session
//                .and().sessionManagement().invalidSessionStrategy(myInvalidSessionStrategy) //会话超时管理
//                .maximumSessions(1) //最大允许登陆数量
//                .maxSessionsPreventsLogin(false) //是否禁止另一个账户登录
//                .expiredSessionStrategy(myExpiredSessionStrategy);   //用户被挤下线的处理
        http
                .authorizeRequests()
                .antMatchers("/", "/test/hello", "/user/login").permitAll()   //设置哪些路径可以直接访问，不需要认证
                .antMatchers("/test/index").hasAuthority("admins")  //当前登录的用户具有admin权限才可访问这个路径（针对一个权限）
                .antMatchers("/test/index2").hasAnyAuthority("admins,manager")   //针对多个权限
                .antMatchers("/test/index3").hasRole("sale") //当用户具有指定的角色才可以访问
                .antMatchers("/test/index4").hasAnyRole("admins,sale")
                .anyRequest().authenticated()
                .and().rememberMe().tokenRepository(persistentTokenRepository())    //设置自动登录
                .tokenValiditySeconds(60 * 60);   //设置有效时长，单位：秒
//                .userDetailsService(myUserDetailsService);

        //允许跨域访问
        http.cors();
        //开启模拟请求，比如API POST测试工具的测试，不开启时，API POST为报403错误
        http.csrf().disable();  //关闭csrf防护
        //将jwt过滤器加入到过滤器链
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        //配置异常处理器
        http.exceptionHandling()
                //配置认证失败处理器
                .authenticationEntryPoint(authenticationEntryPointImpl)
                //配置授权失败处理器
                .accessDeniedHandler(accessDeniedHandlerImpl);

    }

    @Override
    public void configure(WebSecurity web) {
        //对于在header里面增加token等类似情况，放行所有OPTIONS请求。
//        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
        // 该路径不通过SpringSecurity的过滤器链
        web.ignoring().antMatchers("/user/login", "/chat/**");
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
